package cn.edu.lsnu.mbti.service.impl;

import cn.edu.lsnu.mbti.dto.UniversityDto;
import cn.edu.lsnu.mbti.entity.*;
import cn.edu.lsnu.mbti.entity.vo.UniversityVo;
import cn.edu.lsnu.mbti.exception.CustomerException;
import cn.edu.lsnu.mbti.mapper.UniversityMapper;
import cn.edu.lsnu.mbti.service.*;
import cn.edu.lsnu.mbti.util.RedisUtil;
import cn.edu.lsnu.mbti.util.RegionUtils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UniversityServiceImpl extends ServiceImpl<UniversityMapper, University> implements UniversityService {


    public static final String recommendUniversityKey = "MBTI:RECOMMEND_UNIVERSITY:";
    public static final String universityKey = "MBTI:UNIVERSITY:ALL";
    @Resource
    private UniversityMapper universityMapper;
    @Resource
    private RegionService regionService;
    @Resource
    private DicUniversityDepartmentService dicService;
    @Resource
    private DepartmentService departmentService;
    @Resource
    private UniversityMajorService universityMajorService;
    @Resource
    private UniversityUserService universityUserService;
    @Resource
    private MajorService majorService;
    @Resource
    private TypeService typeService;
    @Resource
    private UserService userService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private CategoryService categoryService;


    /**
     * vue后台管理修改院校
     * @param university
     * @return
     */
    @Override
    @Transactional
    public String saveUser(University university) {
        try {
            int result = 0;
            //判断id是否为空
            if (StrUtil.isBlank(university.getId())){
                //空，新增院校
                result = universityMapper.insert(university);
            }else{
                //不为空，修改用户
                result = universityMapper.updateById(university);
            }
            if (result > 0){
                return "保存成功";
            }
        } catch (Exception e) {
            throw new CustomerException("保存失败，请稍后重试");
        }
        throw new CustomerException("保存失败，请稍后重试");
    }

    /**
     * vue后台管理分页查询院校列表
     *
     * @param universityVo
     * @return
     */
    @Override
    public Page<UniversityDto> queryPageList(UniversityVo universityVo) {
        //构造查询条件
        LambdaQueryWrapper<University> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(University::getName, universityVo.getName());
        wrapper.eq(StrUtil.isNotBlank(universityVo.getRegionId()), University::getRegionId, universityVo.getRegionId());
        wrapper.eq(StrUtil.isNotBlank(universityVo.getTypeId()), University::getTypeId, universityVo.getTypeId());
        wrapper.eq(StrUtil.isNotBlank(universityVo.getLevel()), University::getLevel, universityVo.getLevel());
        wrapper.eq(StrUtil.isNotBlank(universityVo.getTeacCharacter()), University::getTeacCharacter, universityVo.getTeacCharacter());
        wrapper.orderByDesc(University::getCreateTime);

        Page<University> universityPage = new Page<>(universityVo.getPageNum(), universityVo.getPageSize());

        //分页查询
        universityPage = this.page(universityPage, wrapper);

        //对象复制
        Page<UniversityDto> universityDtoPage = new Page<>();
        BeanUtils.copyProperties(universityPage, universityDtoPage, "records");

        //封装属性
        universityDtoPage.setRecords(universityPage.
                getRecords().stream().map(this::handleUniversity).collect(Collectors.toList()));

        return universityDtoPage;
    }

    /**
     * 根据专业id查询院校列表
     *
     * @param majorId
     * @return
     */
    @Override
    public List<University> selectUniversityListByMajorId(String majorId) {
        //根据majorId查询university_major表
        LambdaQueryWrapper<UniversityMajor> universityMajorWrapper = new LambdaQueryWrapper<>();
        universityMajorWrapper.eq(StrUtil.isNotBlank(majorId), UniversityMajor::getMajorId, majorId);
        List<UniversityMajor> universityMajorList = universityMajorService.list(universityMajorWrapper);

        //根据结果获取universityId集合
        List<String> universityIdList = universityMajorList.stream().map(obj -> obj.getUniversityId()).collect(Collectors.toList());

        //根据universityId集合查询院校，并返回
        if (universityIdList != null && universityIdList.size() > 0) {
            return this.listByIds(universityIdList);
        }
        return null;
    }

    /**
     * 点击院校名称查询院校的详细信息
     *
     * @param name
     * @return
     */
    @Override
    public UniversityDto selectByNameForDetail(String name) {
        //根据名称查询院校
        LambdaQueryWrapper<University> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(name), University::getName, name);
        University university = this.getOne(wrapper);

        UniversityDto universityDto = this.handleUniversity(university);

        return universityDto;
    }

    /**
     * 查询所有学校列表列表
     *
     * @return
     */
    @Override
    public List<University> selectUniversityList() {
        String jsonStr = (String) redisUtil.get(universityKey);
        if (StrUtil.isNotBlank(jsonStr)) {
            return JSONUtil.toBean(jsonStr, new TypeReference<List<University>>() {
            }, true);
        }
        List<University> universityList = this.list();
        redisUtil.set(universityKey, JSONUtil.toJsonStr(universityList));
        return universityList;
    }

    /**
     * 通过点击专业名称展示院校列表
     * redis 缓存
     *
     * @param userId
     * @param majorId
     * @return
     */
    @Override
    @Transactional
    public List<UniversityDto> selectByRecommend(String majorId, String userId) {

//        //通过查询university_user表，是否已经存在推荐的院校了，如果存在直接在该表查询
//        //构造查询第三张表的查询构造器
//        LambdaQueryWrapper<UniversityUser> universityUserWrapper = new LambdaQueryWrapper<>();
//        universityUserWrapper.eq(UniversityUser::getUserId, userId);
//
//        //查询第三张表
//        List<UniversityUser> universityUserList = universityUserService.list(universityUserWrapper);
//
//        //判断universityUserList
//        if (universityUserList != null && universityUserList.size() > 0) {//已经有推荐了，直接返回结果
//            //遍历universityUserList，查询推荐院校
//            List<UniversityDto> universityDtoList = universityUserList.stream().map(item -> {
//                //根据universityId查询院校
//                University university = this.getById(item.getUniversityId());
//
//                //对象复制
//                UniversityDto universityDto = new UniversityDto();
//                BeanUtils.copyProperties(university, universityDto);
//
//                //查询regionName
//                Region region = regionService.getById(university.getRegionId());
//                universityDto.setRegionName(region.getName());
//
//                return universityDto;
//            }).collect(Collectors.toList());
//
//            return universityDtoList;
//        }
        List<UniversityDto> regionUniversityDtoList;
        //查询有该专业的所有学校
        //构造查询university_major查询构造器
        LambdaQueryWrapper<UniversityMajor> universityMajorWrapper = new LambdaQueryWrapper<>();
        universityMajorWrapper.eq(UniversityMajor::getMajorId, majorId);

        //查询universityMajor集合
        List<UniversityMajor> universityMajorList = universityMajorService.list(universityMajorWrapper);

        //遍历universityMajorList集合，查询学校信息
        List<UniversityDto> allUniversityDtoList = universityMajorList.stream().map(item -> {
            //根据universityId查询
            University university = this.getById(item.getUniversityId());


            //对象复制
            UniversityDto universityDto = new UniversityDto();
            BeanUtils.copyProperties(university, universityDto);
            //查询地区
            if (StrUtil.isNotBlank(university.getRegionId())) {
                Region region = regionService.getById(university.getRegionId());
                universityDto.setRegionName(region.getName());
            }

            return universityDto;
        }).collect(Collectors.toList());

        //遍历allUniversityDtoList，推荐院校
        List<UniversityDto> typeUniversityDtoList = allUniversityDtoList.stream().map(item -> {
            //根据majorId查询专业信息
            Major major = majorService.getById(majorId); //为了获取专业名称

            //查询院校的类型
            Type type = typeService.getById(item.getTypeId());

            String majorNames = type.getMajorName(); //获取类型的专业名称
            String majorName = major.getName(); //所选专业的名称

            //判断所选专业的类型和学校的类型是否相等
            if (!"综合类".equals(type.getName())) { //如果学校不是综合类，就继续判断
                if (majorNames.contains(majorName)) { //所选专业类型与学校的类型相等
                    return item;
                }
            } else { //类型为综合类，直接返回结果
                return item;
            }
            return null;
        }).collect(Collectors.toList());

        //根据地区进行二次筛选
        //遍历typeUniversityDtoList集合
        regionUniversityDtoList = typeUniversityDtoList.stream().map(item -> {
            //查询当前用户信息
            User user = userService.getById(userId); //获取regionId

            //根据regionId查询用户所处的地区
            Region region = regionService.getById(user.getRegionId());


            if (item != null) {
                //判断是否是985或者211
                if (item.getSort() < 51) {
                    return item;
                }

                //判断学校地区是否与当前自己所处地区相同
                if (item.getRegionName().equals(region.getName())) {
                    return item;
                }

                //判断是否为一线城市
                if (RegionUtils.isBigCity(item.getRegionName())) {
                    return item;
                }
            }

            return null;
        }).collect(Collectors.toList());

        //去除null元素
        regionUniversityDtoList.removeAll(Collections.singleton(null));

        //根据sort排序
//        regionUniversityDtoList.sort(Comparator.comparing(UniversityDto::getSort));

        //将推荐的院校保存到university_user表
        List<UniversityUser> universityUsers = new ArrayList<>();
        for (UniversityDto dto : regionUniversityDtoList) {
            //获取参数
            String universityId = dto.getId(); //院校id

            //封装对象
            UniversityUser universityUser = new UniversityUser();
            universityUser.setUserId(userId);
            universityUser.setUniversityId(universityId);
            universityUsers.add(universityUser);
        }
        //保存对象
        universityUserService.saveBatch(universityUsers);

        return regionUniversityDtoList;
    }

    /**
     * 点击查看院校详细信息
     *
     * @param id
     * @return
     */
    @Override
    public UniversityDto selectByIdForDetail(String id) {
        //根据id查询院校基本信息
        University university = this.getById(id);

        UniversityDto universityDto = this.handleUniversity(university);

        return universityDto;
    }

    /**
     * 通过地区名称和级别查询院校信息
     *
     * @param pageNum pageSize universityDto
     * @return
     */
    @Override
    public List<UniversityDto> selectByRegionNameAndSort(int pageNum, int pageSize, UniversityDto universityDto) {

        //作为返回的集合
        List<UniversityDto> universityDtoList = new ArrayList<>();

        //查询的地区
        Region region = new Region();

        //构造查询构造器
        LambdaQueryWrapper<University> universityWrapper = new LambdaQueryWrapper<>();

        //判断级别是否为空
        String level = universityDto.getLevel();
        if (StrUtil.isNotBlank(level)) {
            //构造查询院校的构造器
            if (StrUtil.equals("985", level)) {
                universityWrapper.eq(University::getLevel, level);
            } else if (StrUtil.equals("211", level)) {
                universityWrapper.eq(University::getLevel, level);
            } else {
                universityWrapper.eq(University::getLevel, "双非");
            }
        }

        //判断地区名称是否为空
        if (!"".equals(universityDto.getRegionName()) && universityDto.getRegionName() != null) {    //不为空
            //构造地区的查询构造器
            LambdaQueryWrapper<Region> regionWrapper = new LambdaQueryWrapper<>();
            regionWrapper.eq(Region::getName, universityDto.getRegionName());

            //查询地区
            region = regionService.getOne(regionWrapper);

            //构造查询院校的构造器
            universityWrapper.eq(University::getRegionId, region.getId());
        }

        //设置排序等级，按照sort
        universityWrapper.orderByAsc(University::getSort);

        //分页查询
//        Page<University> page = new Page<>(pageNum, pageSize);
//        Page<University> universityPage = this.page(page, universityWrapper);

        //查询院校
        List<University> universityList = this.list(universityWrapper);
//        List<University> universityList = universityPage.getRecords();

        //遍历universityList集合进行封装处理
        universityDtoList = universityList.stream().map(item -> {
            //实例化universityDto
            UniversityDto dto = new UniversityDto();

            //对象复制
            BeanUtils.copyProperties(item, dto);

            //为dto设置没有封装的regionName
            dto.setRegionName(regionService.getById(dto.getRegionId()).getName());

            //设置typeName
            dto.setTypeName(typeService.getById(dto.getTypeId()).getName());

            return dto;

        }).collect(Collectors.toList());

        return universityDtoList;
    }

    /**
     * 通过名称模糊查询院校
     * redis 缓存数据
     *
     * @param name
     * @return universityDto
     */
    @Override
    public List<UniversityDto> selectByName(String name) {
        //构造查询构造器
        LambdaQueryWrapper<University> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(name), University::getName, name);
        queryWrapper.orderByAsc(University::getSort);

        //查询院校
        List<University> universityList = this.list(queryWrapper);

        //遍历universityList集合，将每个院校基本信息复制
        List<UniversityDto> universityDtoList = universityList.stream().map(item -> {
            UniversityDto universityDto = new UniversityDto();  //实例化universityDto对象

            BeanUtils.copyProperties(item, universityDto);   //对象复制

            //根据regionId去查询region的名称
            Region region = regionService.getById(item.getRegionId());

            //为universityDto设置regionName
            universityDto.setRegionName(region.getName());

            return universityDto;

        }).collect(Collectors.toList());

        return universityDtoList;
    }


    /**
     * 查询学校新闻
     * redis 缓存学校集合信息
     * @return
     */
//    @Override
//    public List<University> news() {
//        List<University> universityList;
//        //从缓存获取院校集合数据
//        String jsonStr = (String) redisUtil.get(universityKey);
//        //判断缓存中是否有数据
//        if (StrUtil.isNotBlank(jsonStr)){
//            //缓存中有数据
//            //将json字符串格式转换为Bean对象
//            universityList = JSONUtil.toBean(jsonStr, new TypeReference<List<University>>() {
//            },true);
//        }else {
//            //缓存中没有数据
//            //构造查询条件
//            LambdaQueryWrapper<University> queryWrapper = new LambdaQueryWrapper<>();
//            queryWrapper.orderByAsc(University::getSort);
//            //查询集合
//            universityList = this.list(queryWrapper);
//            //将数据存储到redis中
//            redisUtil.set(universityKey,JSONUtil.toJsonStr(universityList), Constants.EXPIRE_WEEK);
//        }
//        return universityList;
//
//    }


    /**
     * 查询各个阶段的前列学校
     * 这里因为没有院校的数据，就假设院校的排名
     * 985：20
     * 211：30
     * 双非：50
     *
     * @return
     */
    @Override
    public List<University> popularSchool() {
        //1.构造查询条件
        LambdaQueryWrapper<University> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(University::getSort, 1, 2, 21, 22, 51);
        queryWrapper.orderByAsc(University::getSort);
        //2.查询院校
        List<University> list = this.list(queryWrapper);

        return list;
    }

    public UniversityDto handleUniversity(University university) {
        //对象复制
        UniversityDto universityDto = new UniversityDto();  //实例化universityDto
        BeanUtils.copyProperties(university, universityDto);

        //封装未复制的属性
        //regionName
        //查询地址
        if (StrUtil.isNotBlank(university.getRegionId())) {
            Region region = regionService.getById(university.getRegionId());
            if (BeanUtil.isNotEmpty(region)) {
                //设置regionName
                universityDto.setRegionName(region.getName());
            }
        }

        //设置typeName
        if (StrUtil.isNotBlank(universityDto.getTypeId())) {
            Type type = typeService.getById(universityDto.getTypeId());
            if (BeanUtil.isNotEmpty(type)) {
                //设置regionName
                universityDto.setTypeName(type.getName());

            }
        }

        //departmentList
        //根据universityId查询departmentId
        LambdaQueryWrapper<DicUniversityDepartment> dicWrapper = new LambdaQueryWrapper<>();
        dicWrapper.eq(DicUniversityDepartment::getUniversityId, university.getId());
        //查询dic
        List<DicUniversityDepartment> dicList = Optional.ofNullable(dicService.list(dicWrapper))
                .orElse(new ArrayList<>());
        //遍历dicList，根据departmentId查询院校的学科
        List<Department> departmentList = Optional.of(dicList.stream().map(item -> {
            Department department = new Department();
            //根据departmentId查询学科
            if (StrUtil.isNotBlank(item.getDepartmentId())){
                department = departmentService.getById(item.getDepartmentId());
                //查询专业列表
                LambdaQueryWrapper<UniversityMajor> umQueryWrapper = new LambdaQueryWrapper<>();
                umQueryWrapper.eq(StrUtil.isNotBlank(item.getDepartmentId()),UniversityMajor::getDepartmentId,item.getDepartmentId());
                List<UniversityMajor> universityMajorList = Optional.ofNullable(universityMajorService.list(umQueryWrapper))
                        .orElse(new ArrayList<>());
                List<String> majorIds = universityMajorList.stream().map(obj -> obj.getMajorId()).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(majorIds)){
                    List<Major> majorList = Optional.ofNullable(majorService.listByIds(majorIds)).orElse(new ArrayList<>());
                    department.setMajorList(majorList);
                }
            }
            return department;
        }).collect(Collectors.toList())).orElse(new ArrayList<>());
        //设置departmentList
        universityDto.setDepartmentList(departmentList);

        //majorList
        //根据universityId查询专业list
        //构造查询院校的专业的构造器
        LambdaQueryWrapper<UniversityMajor> universityMajorWrapper = new LambdaQueryWrapper<>();
        universityMajorWrapper.eq(UniversityMajor::getUniversityId, university.getId());
        List<UniversityMajor> universityMajorList = Optional.ofNullable(universityMajorService.list(universityMajorWrapper))
                .orElse(new ArrayList<>());
        List<UniversityMajor> finalUniversityMajorList = Optional.ofNullable(universityMajorList.stream().map(obj -> {
            obj.setCategoryName(categoryService.getById(obj.getCategoryId()).getName());
            return obj;
        }).collect(Collectors.toList())).orElse(new ArrayList<>());
        //设置majorList
        universityDto.setMajorList(finalUniversityMajorList);

        return universityDto;
    }
}
